﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Text.RegularExpressions;
using RAP.Framework.Libary.Configuration;

namespace RAP.Framework.Libary.Utils
{
	/// <summary>
	/// 字符串模版转换类
	/// </summary>
	public class TemplateTranslator
	{
		private static TemplateTranslator _instance = new TemplateTranslator();

		/// <summary>
		/// 获取单例模式的实例对象
		/// </summary>
		public static TemplateTranslator SingletonInstance
		{
			get
			{
				return _instance;
			}
		}

		/// <summary>
		/// 创建一个新的模版实例
		/// </summary>
		public TemplateTranslator( )
		{

		}

		public TemplateTranslator( Regex regex )
		{
			_regex = regex;
			this._templatePattern = regex.ToString();
		}

		/// <summary>
		/// 创建一个新的模版实例
		/// </summary>
		/// <param name="pattern">正则表达式</param>
		/// <param name="compileRegex">是否预编译正则表达式</param>
		public TemplateTranslator( string pattern = null, bool compileRegex = false )
		{
			if ( pattern.IsNotNullOrEmpty() )
			{
				_templatePattern = pattern;
			}
			this.CompileRegex = compileRegex;
		}

		private string _templatePattern = "{%([^}]+)%}";
		private Regex _regex = null;

		/// <summary>
		/// 是否预编译正则表达式
		/// </summary>
		public bool CompileRegex { get; set; }

		/// <summary>
		/// 获取编译后的正则表达式对象
		/// </summary>
		public Regex PatternRegex
		{
			get
			{
				if ( _regex == null )
				{
					var options = RegexOptions.Multiline | RegexOptions.IgnoreCase;
					if ( this.CompileRegex )
					{
						options = options | RegexOptions.Compiled;
					}
					_regex = new Regex( _templatePattern, options );
				}
				return _regex;
			}
		}

		/// <summary>
		/// 获取或设置解析模版的正则表达式
		/// </summary>
		public string TemplatePattern
		{
			get
			{
				return this._templatePattern;
			}
			set
			{
				this._templatePattern = value;
				_regex = null;
			}
		}

		/// <summary>
		/// 指定值获取函数并转换字符串模版
		/// </summary>
		/// <param name="template">字符串模版</param>
		/// <param name="getValueFun">获取字段值的函数</param>
		/// <returns></returns>
		public string TranslateTemplate( string template, Func<string, object> getValueFun )
		{
			if ( this.PatternRegex.IsMatch( template ) )
			{
				var sb = new StringBuilder();
				var intStart = 0;
				var strTmp = string.Empty;

				var matches = this.PatternRegex.Matches( template );
				foreach ( Match match in matches )
				{
					var strValue = string.Empty;
					var fieldName = string.Empty;
					object value = null;
					if ( match.Groups.Count > 0 )
					{
						fieldName = match.Groups[ 1 ].Value;
						value = getValueFun( fieldName );
						if ( value != null )
						{
							strValue = value.ToString();
						}
						strTmp = template.Substring( intStart, match.Index - intStart );
						intStart = match.Index + match.Length;
						sb.Append( strTmp );
						sb.Append( strValue );
					}
				}
				strTmp = template.Substring( intStart );
				sb.Append( strTmp );
				return sb.ToString();
			}
			return template;
		}

		/// <summary>
		/// 执行转换并返回结果
		/// </summary>
		/// <param name="template">字符串模版</param>
		/// <param name="htData">Hashtable数据</param>
		/// <returns></returns>
		public string TranslateTemplate( string template, IDictionary htData )
		{
			return this.TranslateTemplate( template, ( string fieldName ) =>
		   {
			   return htData.GetValue( fieldName );
		   } );
		}

		/// <summary>
		/// 执行转换并返回结果
		/// </summary>
		/// <param name="template">字符串模版</param>
		/// <param name="obj">对象</param>
		/// <returns></returns>
		public string TranslateTemplate( string template, object obj )
		{
			return this.TranslateTemplate( template, ( string fieldName ) =>
		   {
			   if ( fieldName == "value" )
			   {
				   return obj;
			   }
			   return obj.GetValue( fieldName );
		   } );
		}

		/// <summary>
		/// 转换AppSettings配置中的参数
		/// </summary>
		/// <param name="template"></param>
		/// <returns></returns>
		public string TranslateTemplate( string template )
		{
			return this.TranslateTemplate( template, ( string fieldName ) =>
		   {
			   return ConfigurationManager.AppSettings[ fieldName ];
		   } );
		}

		/// <summary>
		/// 编译指定的模版，获取编译后的Item集合
		/// </summary>
		/// <param name="template">字符串模版</param>
		/// <returns></returns>
		public virtual IList<CompiledItem> CompileTemplateItems( string template )
		{
			var compiledItems = new List<CompiledItem>();
			if ( this.PatternRegex.IsMatch( template ) )
			{
				//将正则表达式匹配的结果编译为一个Func对象
				var intStart = 0;
				var matches = this.PatternRegex.Matches( template );
				foreach ( Match match in matches )
				{
					var fieldName = string.Empty;
					var strTmp = string.Empty;
					if ( match.Groups.Count > 0 )
					{
						fieldName = match.Groups[ 1 ].Value;
						strTmp = template.Substring( intStart, match.Index - intStart );
						intStart = match.Index + match.Length;
						if ( strTmp != null && strTmp.Length > 0 )
						{
							compiledItems.Add( new CompiledItem() { Value = strTmp } );
						}
						compiledItems.Add( new CompiledItem() { Type = CompiledItem.ItemTypeEnums.Field, Value = fieldName } );
					}
				}
				compiledItems.Add( new CompiledItem() { Value = template.Substring( intStart ) } );
			}
			else
			{
				compiledItems.Add( new CompiledItem() { Value = template } );
			}
			return compiledItems;
		}

		/// <summary>
		/// 将正则表达式匹配的结果编译为一个Func对象
		/// </summary>
		/// <param name="template">字符串模版</param>
		/// <param name="getValueFun">获取字段值的函数</param>
		/// <returns>返回编译后的Lambda表达式函数</returns>
		public Func<string> CompileTemplate( string template, Func<string, object> getValueFun )
		{
			var compiledItems = this.CompileTemplateItems( template );
			//将正则表达式匹配的结果编译为一个Func对象
			//返回Func对象
			return ( ) =>
			{
				var sb = new StringBuilder();
				foreach ( var item in compiledItems )
				{
					if ( item.Type == 0 )
					{
						sb.Append( item.Value );
					}
					else
					{
						var value = getValueFun( item.Value );
						if ( value != null )
						{
							sb.Append( value );
						}
					}
				}
				return sb.ToString();
			};
		}

		/// <summary>
		/// 将正则表达式匹配的结果编译为一个Func对象，返回一个Func&lt;string, string>类型参数的Func
		/// </summary>
		/// <param name="template">字符串模版</param>
		/// <param name="compiledFunc">编译后的函数</param>
		/// <returns></returns>
		public void CompileTemplate( string template, out Func<Func<string, string>, string> compiledFunc )
		{
			var compiledItems = this.CompileTemplateItems( template );
			//将正则表达式匹配的结果编译为一个Func对象
			//返回Func对象
			compiledFunc = ( getValue ) =>
			{
				var sb = new StringBuilder();
				foreach ( var item in compiledItems )
				{
					if ( item.Type == CompiledItem.ItemTypeEnums.Const )
					{
						sb.Append( item.Value );
					}
					else
					{
						var value = getValue( item.Value );
						if ( value != null )
						{
							sb.Append( value );
						}
					}
				}
				return sb.ToString();
			};
		}

		/// <summary>
		/// 将正则表达式匹配的结果编译为一个Func对象，返回一个带Object类型参数的Func
		/// </summary>
		/// <param name="template">字符串模版</param>
		/// <returns></returns>
		public Func<object, string> CompileTemplate( string template )
		{
			var compiledItems = this.CompileTemplateItems( template );
			//将正则表达式匹配的结果编译为一个Func对象
			//返回Func对象
			return ( data ) =>
			{
				var sb = new StringBuilder();
				foreach ( var item in compiledItems )
				{
					if ( item.Type == CompiledItem.ItemTypeEnums.Const )
					{
						sb.Append( item.Value );
					}
					else
					{
						var value = data.GetValue( item.Value );
						if ( value != null )
						{
							sb.Append( value );
						}
					}
				}
				return sb.ToString();
			};
		}

		#region CompiledItem
		/// <summary>
		/// 模版编译后的Item
		/// </summary>
		public class CompiledItem
		{
			/// <summary>
			/// 
			/// </summary>
			public enum ItemTypeEnums : int
			{
				/// <summary>
				/// 字符串常量
				/// </summary>
				Const = 0,

				/// <summary>
				/// 需要取值的字段
				/// </summary>
				Field = 1
			}

			/// <summary>
			/// 
			/// </summary>
			public CompiledItem( )
			{
				this.Type = ItemTypeEnums.Const;
			}

			/// <summary>
			/// Item的值类型。0：字符串，1：字段名称
			/// </summary>
			public ItemTypeEnums Type { get; set; }

			/// <summary>
			/// Item的值
			/// </summary>
			public string Value { get; set; }
		}
		#endregion CompiledItem
	}
}